package cn.vconinfo.base.utils;

import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 
 * 
 * @author Administrator
 * @version $Id: DateUtil.java, v 0.1 2016-10-14 下午3:24:01 Administrator Exp $
 */
public final class DateUtil {

    private static final HashMap<String, String> DATE_REG_FORMAT = new HashMap();
    public static final String YY = "20";

    public static final String YYYMMDDHHMMMSS = "yyyy-MM-dd HH:mm:ss";
    
    public static final String YYY_MM_DDHHMMMSS = "yyyy/MM/dd HH:mm:ss";
    
    public static final String YYMMDDHHMMMSS = "yy-MM-dd HH:mm:ss";

    public static final String YYYY_MM_dd = "yyyy-MM-dd";

    public static final String YYYYMMDD = "yyyyMMdd";

    public static final String YYYYMMDDHHMM = "yyyy_MM_dd HH:mm";

    public static final String YYMMDD = "yyMMdd";

    public static final String YY_MM_DD = "yy-MM-dd";

    public static final String HHMMSS = "HH:mm:ss";

    public static final String YYYYMMDDEEEHHMMSS = "yyyy-MM-dd EEE HH:mm:ss";

    public static final String YYYY = "yyyy";
    
    public static final String YYYYMM = "yyyyMM";
    
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    
    public static final String yyyy_mm_dd = "yyyy/MM/dd";

    static {
        DATE_REG_FORMAT.put("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", "yyyy-MM-dd HH:mm:ss");
        DATE_REG_FORMAT.put("[0-9]{4}-[0-9]{2}-[0-9]{2}", "yyyy-MM-dd");
        DATE_REG_FORMAT.put("[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}", "yyyy-MM-dd HH:mm");
        DATE_REG_FORMAT.put("[0-9]{4}[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2}[0-9]{2}", "yyyyMMddHHmmss");
        DATE_REG_FORMAT.put("[0-9]{4}[0-9]{2}[0-9]{2}", "yyyyMMdd");
        DATE_REG_FORMAT.put("[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", "yyyy/MM/dd HH:mm:ss");
        DATE_REG_FORMAT.put("[0-9]{4}/[0-9]{2}/[0-9]{2}", "yyyy/MM/dd");
        DATE_REG_FORMAT.put("[0-9]{4}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}", "yyyy/MM/dd HH:mm");
    }

    public static String getCurrentDateStr() {
        Calendar cal = Calendar.getInstance();
        Date currDate = cal.getTime();

        return format(currDate);
    }

    public static Date parse(String datetime, String pattern) {

        if (StringUtils.isEmpty(datetime) || StringUtils.isEmpty(pattern)) {
            return null;
        }

        SimpleDateFormat dateFromat = new SimpleDateFormat();
        dateFromat.applyPattern(pattern);

        try {
            return dateFromat.parse(datetime);
        } catch (ParseException e) {
            return null;
        }

    }

    public static Date parseUS(String datetime) {
        return parseUS(datetime, YYYYMMDDEEEHHMMSS);
    }

    public static Date parseUS(String datetime, String pattern) {
        if (StringUtils.isEmpty(datetime) || StringUtils.isEmpty(pattern)) {
            return null;
        }

        SimpleDateFormat dateFromat = new SimpleDateFormat(pattern, Locale.US);

        try {
            return dateFromat.parse(datetime);
        } catch (ParseException e) {
            return null;
        }
    }

    public static String getCurrentDateStr(String strFormat) {
        Calendar cal = Calendar.getInstance();
        Date currDate = cal.getTime();

        return format(currDate, strFormat);
    }

    public static String format(Date datetime, String pattern) {
        if (datetime == null || StringUtils.isEmpty(pattern))
            return null;

        try {
            SimpleDateFormat dateFromat = new SimpleDateFormat();
            dateFromat.applyPattern(pattern);
            return dateFromat.format(datetime);
        } catch (Exception e) {
            return null;
        }

    }

    public static String format(Date dateTime) {
        return format(dateTime, YYYY_MM_dd);
    }

    public static Date addMinuts(Date date, int minuts) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + minuts);

        return calendar.getTime();
    }

    /**
     * 计算二个时间相差的秒钟
     * 
     * @param d1
     * @param d2
     * @return
     */
    public static long getDistanceSecond(Date d1, Date d2) {
        DateFormat df = new SimpleDateFormat(YYYMMDDHHMMMSS);
        try {
            long t1 = df.parse(df.format(d1)).getTime();
            long t2 = df.parse(df.format(d2)).getTime();

            return (t2 - t1) / 1000;

        } catch (ParseException e) {

            return 0;
        }

    }

    /**
     * 计算二个时间相差的分钟
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static long getDistanceMinute(Date startDate, Date endDate) {
        DateFormat df = new SimpleDateFormat(YYYMMDDHHMMMSS);
        try {
            long t1 = df.parse(df.format(startDate)).getTime();
            long t2 = df.parse(df.format(endDate)).getTime();

            return (t2 - t1) / (1000*60);

        } catch (ParseException e) {

            return 0;
        }

    }

    public static Date addDay(Date date, int days) {
        Calendar startDT = Calendar.getInstance();
        startDT.setTime(date);
        startDT.add(Calendar.DAY_OF_MONTH, days);

        return startDT.getTime();
    }

    /**
     * 时间增加N秒
     * 
     * @param date
     * @param seconds
     * @return
     */
    public static Date addSecond(Date date, int seconds) {
        Calendar startDT = Calendar.getInstance();
        startDT.setTime(date);
        startDT.add(Calendar.SECOND, seconds);

        return startDT.getTime();
    }

    /**
     * 计算当前时间几小时之后的时间
     *
     * @param date
     * @param hours
     * @return
     */
    public static Date addHours(Date date, long hours) {
        return addMinutes(date, hours * 60);
    }

    /**
     * 计算当前时间几分钟之后的时间
     *
     * @param date
     * @param minutes
     * @return
     */
    public static Date addMinutes(Date date, long minutes) {
        return addSeconds(date, minutes * 60);
    }

    /**
     * 计算当前时间N秒之后的时间
     * @param date
     * @param secs
     * @return
     */

    public static Date addSeconds(Date date, long secs) {
        return new Date(date.getTime() + (secs * 1000));
    }

    /**
     * 
     * @param date
     * @param seconds
     * @return
     */
    public static Date subSecond(Date date, int seconds) {
        seconds = 0 - seconds;
        return addSecond(date, seconds);
    }

    /**
     * 奖期顺延计算两个时间相差的天数
     * 
     * @param start
     *            开始时间
     * @param end
     *            结束时间
     * @return 天数
     */
    public static int issueDateParse(String start, String end) {
        if (StringUtils.isBlank(start) && StringUtils.isBlank(end)) {
            return 0;
        }
        Date tempStart = getWeeHourDate(parse(start, YYYYMMDD));
		Date tempEnd = getWeeHourDate(parse(end, YYYYMMDD));
		
        Calendar caStart = Calendar.getInstance();
        caStart.setTime(tempStart);
        long time1 = caStart.getTimeInMillis();

        Calendar caEnd = Calendar.getInstance();
        caEnd.setTime(tempEnd);
        long time2 = caEnd.getTimeInMillis();
        long betweenDays = (time2 - time1) / (1000 * 3600 * 24);
        
		return Integer.parseInt(String.valueOf(betweenDays));
    }
    
    /**
     * 计算两个时间相差的天数
     * 
     * @param start 开始时间
     * @param end 结束时间
     * @return 天数
     */
	public static int issueDateParse(Date start, Date end) {
		Date tempStart = getWeeHourDate(start);
		Date tempEnd = getWeeHourDate(end);
		Calendar cal = Calendar.getInstance();
		cal.setTime(tempStart);
		long time1 = cal.getTimeInMillis();
		cal.setTime(tempEnd);
		long time2 = cal.getTimeInMillis();
		long betweenDays = (time2 - time1) / (1000 * 3600 * 24);

		return Integer.parseInt(String.valueOf(betweenDays));
	}
    
    /**
     *  计算两个时间之间相差的小时数
     * 
     * @param start
     * @param end
     * @return
     */
    public static float issueHourParse(Date start, Date end) {
        if(start == null || end == null) {
            return 0l;
        }
        long between = (end.getTime() - start.getTime())/1000; //除以1000是为了转换成秒
//        return between%(24*3600)/3600;
        
        float hourInter = between%(24*3600);
       BigDecimal hourParse = cn.vconinfo.base.utils.StringUtils.string2BigDecimal(cn.vconinfo.base.utils.StringUtils.null2Str(hourInter))
               .divide(cn.vconinfo.base.utils.StringUtils.string2BigDecimal("3600"), 5, RoundingMode.HALF_UP);
       
        return hourParse.floatValue();
    }
    
    /**
     * 获取两个日期的月份差
     * 
     * @param maxDate
     *            大日期
     * @param minDate
     *            小日期
     * @return
     */
    public static int getMonthDiff(Date maxDate, Date minDate) {
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.setTime(maxDate);
        c2.setTime(minDate);
        if (c1.getTimeInMillis() < c2.getTimeInMillis())
            return 0;
        int year1 = c1.get(Calendar.YEAR);
        int year2 = c2.get(Calendar.YEAR);
        int month1 = c1.get(Calendar.MONTH);
        int month2 = c2.get(Calendar.MONTH);
        int day1 = c1.get(Calendar.DAY_OF_MONTH);
        int day2 = c2.get(Calendar.DAY_OF_MONTH);
        int yearInterval = year1 - year2;
        if (month1 < month2 || month1 == month2 && day1 < day2)
            yearInterval--;
        int monthInterval = (month1 + 12) - month2;
        if (day1 < day2)
            monthInterval--;
        monthInterval %= 12;
        return yearInterval * 12 + monthInterval;
    }
    
    public static Integer getDateIntVal(String datetime, String pattern) {
        if (datetime == null || StringUtils.isEmpty(pattern))
            return null;
        try {
            SimpleDateFormat dateFromat = new SimpleDateFormat();
            dateFromat.applyPattern(pattern);
            return Integer.valueOf(format(dateFromat.parse(datetime),YYYYMMDD));
        } catch (Exception e) {
            return null;
        }
    }
    
    public static Date setCurrentTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        Calendar nowd = Calendar.getInstance();
        nowd.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, nowd.get(Calendar.HOUR_OF_DAY));
        calendar.set(Calendar.MINUTE, nowd.get(Calendar.MINUTE));
        calendar.set(Calendar.SECOND, nowd.get(Calendar.SECOND));
        
        return calendar.getTime();
    }
    
    /**
     * 获取零点日期时间
     * 
     * @param date
     * @return
     */
    public static Date getWeeHourDate(Date date) {
        if(date == null)
            return null;
        Calendar c1 = Calendar.getInstance();
        c1.setTime(parse(format(date), YYYY_MM_dd));
        c1.set(Calendar.HOUR_OF_DAY, 0);
        c1.set(Calendar.MINUTE, 0);
        c1.set(Calendar.SECOND, 0);
        
        return c1.getTime();
    }
    
    /**
     * 获取该时间的午夜日期
     * 
     * @param date
     * @return
     */
    public static Date getMidnightDate(Date date) {
        if(date == null)
            return null;
        Calendar c1 = Calendar.getInstance();
        c1.setTime(date);
        c1.set(Calendar.HOUR_OF_DAY, 23);
        c1.set(Calendar.MINUTE, 59);
        c1.set(Calendar.SECOND, 59);
        
        return c1.getTime();
    }
    
    /**
     *  获取某个月的第一天
     * 
     * @param date
     * @return
     */
    public static Date getFirstDayOfMonth(Date date) {
        if(date == null) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //获取某月最小天数
        int firstDay = calendar.getMinimum(Calendar.DATE);
        //设置日历中月份的最小天数 
        calendar.set(Calendar.DAY_OF_MONTH,firstDay); 
        
        return calendar.getTime();
    }
    
    /**
     *  获取某个月的最后一天
     * 
     * @param date
     * @return
     */
    public static Date getLastDayOfMonth(Date date) {
        if(date == null) {
            return date;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        //获取某月最大天数
        int lastDay = calendar.getActualMaximum(Calendar.DATE);
        //设置日历中月份的最大天数  
        calendar.set(Calendar.DAY_OF_MONTH, lastDay); 

        return calendar.getTime();
    }
    
    /*public static Integer getDateIntVal(String datetime) {
        if (datetime == null)
            return null;
        datetime = datetime.replace("-", "").replace("/", "").substring(0,8);
        return Integer.valueOf(datetime);
    }*/

    /**
     *  匹配所有提供的日期类型
     *
     * @param dateStr
     * @return
     */
    public static Date formatAll(String dateStr) {
        Iterator iterator = DATE_REG_FORMAT.entrySet().iterator();

        Map.Entry entry;
        do {
            if (!iterator.hasNext()) {
                return null;
            }

            entry = (Map.Entry)iterator.next();
        } while(!Pattern.compile((String)entry.getKey()).matcher(dateStr).matches());

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern((String)entry.getValue());
        if (!"yyyy-MM-dd".equals(entry.getValue()) && !"yyyyMMdd".equals(entry.getValue())) {
            LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter);
            return localDateTime2Date(localDateTime);
        } else {
            LocalDate localDate = LocalDate.parse(dateStr, formatter);
            return localDate2Date(localDate);
        }
    }

    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        Instant instant = localDateTime.toInstant(OffsetDateTime.now().getOffset());
        return Date.from(instant);
    }

    public static Date localDate2Date(LocalDate localDate) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
        return Date.from(instant);
    }

    public static void main(String[] args) {

        SimpleDateFormat dateFromat = new SimpleDateFormat();
        dateFromat.applyPattern(YYYMMDDHHMMMSS);

        try {
            System.out.println(dateFromat.parse("2021-11-18 06:00:48.216Z"));
        } catch (ParseException ex) {
            ex.printStackTrace();
        }

    }
}
